package com.edu.杂七杂八;

import java.io.IOException;

/**
 * 字符串常量池的探讨
 * String.intern()方法：（比较的是StringValue）返回字符串对象的规范表示。
 *                      最初为空的字符串池由String类私有维护。
 *                      调用intern方法时，如果池已经包含equals(Object)方法确定的此String对象的字符串，则返回池中的字符串。
 *                      否则，将此String对象添加到池中，并返回对此String对象的引用。
 * 1.8 将这个字符串对象尝试放入串池，如果有则并不会放入，如果没有则放入串池， 会把串池中的对象返回(即存放对象的指针)
 * 1.6 将这个字符串对象尝试放入串池，如果有则并不会放入，如果没有会把此对象复制一份，放入串池， 会把串池中的对象返回
 * (即复制一份StringValue到StringTable中)
 *
 * 设置参数:
 *  jdk1.8:-Xmx10m -XX:-UseGCOverheadLimit //具体解释看文档说明
 *  jdk1.6:-XX:MaxPermSize=10m
 *
 * 可以使用String.intern()方法来进行StringTable的优化
 * @作者 five-five
 * @创建时间 2021/5/24
 */
public class StringTable {
    //常量池的信息，都会被加载在运行时常量池中，这是a,b,ab都是常量池中的符号，还没有变成java中的字符串对象
    //变为String字符串时，储存在StringTable(字符串常量池)中，以key-value(hashTable)的形式存储，不能扩容
    //用到字符串才会存储(结合懒汉模式分析)

    public static void main(String[] args) throws IOException {
        //StringTable["a","b","ab"]
        String s1 = "a";
        String s2 = "b";
        String s3 = "a" + "b";//(编译器优化)javac在编译期间的优化，他认为ab是常量，结果已经在编译期间确定为ab，所以直接使用常量池的引用(共享>创建)
        String s4 = s1 + s2;//实际上是想创造了StringBuilder对象,并调用append("a").append("b").toString();相当于创建了新的值为"ab"的对象
        String s5 = "ab";
        String s6 = s4.intern();
        // 问
        System.out.println(s3 == s4);//false
        System.out.println(s3 == s5);//true
        System.out.println(s3 == s6);//true
        System.out.println(s6==s4);//false
        //注意下面这一段代码会分成两端执行
        // 第一段new String("c")会将"c"字符串丢入在StringTable中，
        // 第二段new String("d")会将"d"字符串丢入在StringTable中(注意不是"cd")
        //此时x2是在堆中的对象[或者说引用指针会更具体一点](new String("cd") 创建了三个对象 new String("c"); new String("d"); new String("cd") )
        String x2 = new String("c") + new String("d");//new String("cd")
        String x1 = "cd";
        x2.intern();//此时cd中存在与StringTable中
        // 问，如果调换了【最后两行代码】的位置呢？为true
        // 如果是jdk1.6呢？为false
        System.out.println(x1 == x2);//false
        //使用jprofiler检测一下
        System.in.read();
    }
}
